﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media.Imaging;

namespace PP.PaintLib
{
    public class PPGIF
    {
        /// <summary>
        /// 保存为GIF文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <param name="format">图片格式</param>
        /// <returns>true:成功 false:失败</returns>
        public static bool SaveAsGIF(string filePath, int width = 50, int height = 50, string format = "PPGIF")
        {
            try
            {
                width = width <= 0 ? 50 : width;
                height = height <= 0 ? 50 : height;

                string fileDirectory = Path.GetDirectoryName(filePath);
                string fileSavePath = Path.Combine(fileDirectory, Path.GetFileNameWithoutExtension(filePath)) + $"_2.{format.ToLower()}";

                SetGifOrDiffSize(filePath, fileSavePath, width, height, format);

                Process.Start("explorer.exe", fileDirectory);
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"转换失败！错误信息：{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }

        /// <summary>
        /// 设置GIF大小
        /// </summary>
        /// <param name="path">图片路径</param>
        /// <param name="destination">输出GIF文件路径</param>
        /// <param name="width">宽</param>
        /// <param name="height">高</param>
        /// <param name="format">图片格式</param>
        private static void SetGifOrDiffSize(string path,string destination, int width, int height, string format = "PPGIF")
        {
            using (Image gif = new Bitmap(width, height))
            using (Image frame = new Bitmap(width, height))
            using (Image res = Image.FromFile(path))
            using (Graphics g = Graphics.FromImage(gif))
            using (Graphics gFrame = Graphics.FromImage(frame))
            {
                Rectangle rg = new Rectangle(0, 0, width, height);
                foreach (Guid gd in res.FrameDimensionsList)
                {
                    FrameDimension fd = new FrameDimension(gd);

                    //因为是缩小GIF文件所以这里要设置为Time，如果是TIFF这里要设置为PAGE，因为GIF以时间分割，TIFF为页分割 
                    FrameDimension f = format.ToUpper() == "PPGIF" ? FrameDimension.Time : FrameDimension.Page;
                    ImageFormat imageFormat = format.ToUpper() == "PPGIF" ? ImageFormat.Gif : ImageFormat.Tiff;

                    int count = res.GetFrameCount(fd);
                    ImageCodecInfo codecInfo = GetEncoder(imageFormat);
                    System.Drawing.Imaging.Encoder encoder = System.Drawing.Imaging.Encoder.SaveFlag;
                    EncoderParameters encoderParameters = null;

                    for (int i = 0; i < count; i++)
                    {
                        res.SelectActiveFrame(f, i);
                        if (i == 0)
                        {
                            g.DrawImage(res, rg);

                            encoderParameters = new EncoderParameters(1);
                            //第一帧需要设置为MultiFrame 
                            encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.MultiFrame);
                            bindProperty(res, gif);
                            gif.Save(destination, codecInfo, encoderParameters);//第一张图片存进去
                        }
                        else
                        {
                            gFrame.DrawImage(res, rg);

                            encoderParameters = new EncoderParameters(1);
                            //如果是GIF这里设置为FrameDimensionTime，如果为TIFF则设置为FrameDimensionPage 
                            long fencoderValue = format.ToUpper() == "PPGIF" ? (long)EncoderValue.FrameDimensionTime : (long)EncoderValue.FrameDimensionPage;
                            encoderParameters.Param[0] = new EncoderParameter(encoder, fencoderValue);
                            bindProperty(res, frame);
                            gif.SaveAdd(frame, encoderParameters);//原图片集里继续追加
                        }
                    }

                    encoderParameters = new EncoderParameters(1);
                    encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.Flush);
                    gif.SaveAdd(encoderParameters);
                }
            }
        }

        /// <summary> 
        /// 将源图片文件里每一帧的属性设置到新的图片对象里 
        /// </summary> 
        /// <param name="sourseImage">源图片帧</param> 
        /// <param name="newImage">新的图片帧</param> 
        private static void bindProperty(Image sourseImage, Image newImage)
        {
            //这个东西就是每一帧所拥有的属性，可以用GetPropertyItem方法取得，这里为完全复制原有属性，所以直接赋值了 
            //顺便说一下，这个属性里包含每帧间隔的秒数和透明背景调色板等设置，这里具体哪个值对应哪个属性，大家自己在msdn搜索GetPropertyItem方法说明就有了
            for (int i = 0; i < sourseImage.PropertyItems.Length; i++)
            {
                newImage.SetPropertyItem(sourseImage.PropertyItems[i]);
            }
        }

        /// <summary>
        /// 获取图片格式编码
        /// </summary>
        /// <param name="format">图片格式</param>
        /// <returns></returns>
        private static ImageCodecInfo GetEncoder(ImageFormat format)
        {

            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();

            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.FormatID == format.Guid)
                {
                    return codec;
                }
            }
            return null;
        }

        /// <summary>
        /// 图片集合 转为 PPGIF
        /// </summary>
        /// <param name="imagePaths">原图片集合</param>
        /// <param name="outputPath">GIF输出路径</param>
        /// <param name="gifWidth">宽度</param>
        /// <param name="gifHeight">高度</param>
        /// <param name="timeout">每张图的时间间隔</param>
        /// <param name="IsLoop">是否循环播放</param>
        /// <exception cref="ArgumentException"></exception>
        public static bool ImagesToGIF(string[] imagePaths, string outputPath, int gifWidth, int gifHeight, short timeout = 100, bool IsLoop = true)
        {
            // 参数校验
            if (imagePaths == null || imagePaths.Length == 0)
            {
                throw new ArgumentException("未提供图像.");
            }

            if (string.IsNullOrWhiteSpace(outputPath))
            {
                throw new ArgumentException("输出路径无效.");
            }

            if (gifWidth <= 0 || gifHeight <= 0)
            {
                throw new ArgumentException("PPGIF 尺寸无效.");
            }

            if (timeout <= 0)
            {
                throw new ArgumentException("帧延迟应大于 0.");
            }

            GifBitmapEncoder gEnc = new GifBitmapEncoder();

            for (int i = 0; i < imagePaths.Length; i++)
            {
                Thread.Sleep(timeout);

                using (Image img = PPImage.ResizeImage(Image.FromFile(imagePaths[i]), new System.Drawing.Size(gifWidth, gifHeight)))
                {
                    Bitmap bmpImage = (Bitmap)img;
                    var bmp = bmpImage.GetHbitmap();

                    var src = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                        bmp,
                        IntPtr.Zero,
                        Int32Rect.Empty,
                        BitmapSizeOptions.FromEmptyOptions());

                    gEnc.Frames.Add(BitmapFrame.Create(src));
                }
            }


            using (FileStream fs = new FileStream(outputPath, FileMode.Create))
            {
                gEnc.Save(fs);
            }

            return true;
        }

        /// <summary>
        /// GIF拆分后保存为多个图片
        /// </summary>
        /// <param name="gifPath">GIF路径</param>
        /// <param name="imageSaveDir">拆分后保存图片的目录</param>
        /// <param name="format">保存图片格式</param>
        public static void GIFToImages(string gifPath, string imageSaveDir,ImageFormat format)
        {
            Image imgGif = Image.FromFile(gifPath); // 获取图片对象
            // 先判断图片是否是动画图片（gif）
            if (ImageAnimator.CanAnimate(imgGif))
            {
                // 查看存放图片的目录是否存在，不存在的话就创建该目录
                if (!Directory.Exists(imageSaveDir))
                {
                    Directory.CreateDirectory(imageSaveDir);
                }
                FrameDimension imgFrmDim = new FrameDimension(imgGif.FrameDimensionsList[0]);
                int nFdCount = imgGif.GetFrameCount(imgFrmDim); // 获取帧数
                for (int i = 0; i < nFdCount; i++)
                {
                    // 把每一帧保存为jpg图片
                    imgGif.SelectActiveFrame(imgFrmDim, i);
                    string imgSaveName = Path.Combine(imageSaveDir, $"{Path.GetFileNameWithoutExtension(gifPath)}{i + 1}.{format.ToString()}");
                    imgGif.Save(imgSaveName, format);
                }
            }
        }

    }
}
